<!doctype html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
    <meta name="theme-color" content="#0b1220" />
    <title>数字炸弹</title>
    <link rel="preconnect" href="https://fonts.googleapis.com" />
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
    <link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;600;700&family=Inter:wght@400;600;700&display=swap" rel="stylesheet" />
    <style>
      :root {
        --bg: #0b1220;
        --bg-soft: #0f172a;
        --card: #0b1220;
        --text: #e5e7eb;
        --muted: #9ca3af;
        --primary: #60a5fa;
        --primary-600: #3b82f6;
        --accent: #22d3ee;
        --danger: #f87171;
        --ring: 0 0 0 2px rgba(96,165,250,0.55), 0 0 30px rgba(34,211,238,0.25);
      }

      * {
        box-sizing: border-box;
      }

      html, body {
        margin: 0;
        padding: 0;
        background: radial-gradient(1200px 800px at 70% -20%, rgba(34,211,238,0.12), transparent),
                    radial-gradient(1000px 700px at -20% 20%, rgba(59,130,246,0.15), transparent),
                    var(--bg);
        color: var(--text);
        font-family: Inter, system-ui, -apple-system, Segoe UI, Roboto, Noto Sans, Helvetica, Arial, "Apple Color Emoji", "Segoe UI Emoji";
        -webkit-tap-highlight-color: transparent;
      }

      .app {
        min-height: 100vh;
        display: flex;
        flex-direction: column;
        align-items: center;
        padding: env(safe-area-inset-top) 16px env(safe-area-inset-bottom) 16px;
      }

      .app__header {
        text-align: center;
        margin-top: 12px;
        margin-bottom: 12px;
      }

      .app__title {
        font-family: Orbitron, Inter, system-ui, sans-serif;
        letter-spacing: 0.04em;
        font-weight: 700;
        font-size: clamp(22px, 5vw, 32px);
        margin: 8px 0 4px 0;
        background: linear-gradient(90deg, var(--text), var(--accent));
        -webkit-background-clip: text;
        background-clip: text;
        color: transparent;
      }

      .app__subtitle {
        color: var(--muted);
        font-size: 14px;
        margin: 0 0 12px 0;
      }

      .controls {
        width: 100%;
        display: flex;
        justify-content: center;
        position: sticky;
        top: 0;
        z-index: 10;
        padding: 8px 0 12px 0;
        backdrop-filter: blur(8px);
      }

      .button {
        appearance: none;
        border: none;
        border-radius: 12px;
        padding: 12px 18px;
        font-size: 16px;
        font-weight: 600;
        letter-spacing: 0.02em;
        color: #0b1220;
        background: linear-gradient(180deg, var(--primary), var(--primary-600));
        box-shadow: 0 6px 18px rgba(59,130,246,0.35), inset 0 0 0 1px rgba(255,255,255,0.2);
        cursor: pointer;
        transition: transform 0.08s ease, filter 0.2s ease, box-shadow 0.2s ease;
      }

      .button:active {
        transform: translateY(1px) scale(0.99);
        filter: brightness(0.96);
      }

      .button--primary:focus-visible {
        outline: none;
        box-shadow: var(--ring);
      }

      .board__wrapper {
        width: 100%;
        max-width: 520px;
        padding: 8px 6px 24px 6px;
      }

      .board {
        display: grid;
        grid-template-columns: repeat(10, 1fr);
        gap: 6px;
      }

      .cell {
        position: relative;
        aspect-ratio: 1 / 1;
        border-radius: 10px;
        background: linear-gradient(180deg, rgba(30,41,59,0.9), rgba(15,23,42,0.9));
        border: 1px solid rgba(148,163,184,0.1);
        color: var(--text);
        display: flex;
        align-items: center;
        justify-content: center;
        font-weight: 700;
        font-size: clamp(14px, 3.6vw, 18px);
        user-select: none;
        -webkit-user-select: none;
        cursor: pointer;
        transition: transform 0.1s ease, background 0.2s ease, border-color 0.2s ease, opacity 0.25s ease;
      }

      .cell:hover {
        transform: translateY(-1px);
      }

      .cell:active {
        transform: translateY(0);
      }

      .cell--hidden {
        opacity: 0.1;
        pointer-events: none;
      }

      .cell--hit {
        background: linear-gradient(180deg, rgba(34,197,94,0.35), rgba(21,128,61,0.35));
        border-color: rgba(34,197,94,0.6);
        animation: pulse 0.9s ease 1;
      }

      @keyframes pulse {
        0% { box-shadow: 0 0 0 0 rgba(34,197,94,0.0); }
        30% { box-shadow: 0 0 0 16px rgba(34,197,94,0.15); }
        100% { box-shadow: 0 0 0 0 rgba(34,197,94,0.0); }
      }

      .overlay {
        position: fixed;
        inset: 0;
        display: grid;
        place-items: center;
        background: radial-gradient(600px 400px at 50% 50%, rgba(34,197,94,0.1), transparent), rgba(0,0,0,0.35);
        opacity: 0;
        pointer-events: none;
        transition: opacity 0.25s ease;
      }

      .overlay[aria-hidden="false"] {
        opacity: 1;
        pointer-events: auto;
      }

      .overlay__content {
        text-align: center;
        padding: 18px 20px;
        background: rgba(2,6,23,0.65);
        border: 1px solid rgba(148,163,184,0.18);
        border-radius: 14px;
        box-shadow: 0 18px 60px rgba(0,0,0,0.4);
        backdrop-filter: blur(10px);
      }

      .overlay__text {
        font-family: Orbitron, Inter, system-ui, sans-serif;
        font-size: 28px;
        font-weight: 700;
        letter-spacing: 0.06em;
      }

      .overlay__hint {
        margin-top: 6px;
        color: var(--muted);
        font-size: 14px;
      }

      @media (hover: none) {
        .cell:hover { transform: none; }
      }
    </style>
  </head>
  <body>
    <main class="app" aria-live="polite">
      <header class="app__header">
        <h1 class="app__title" aria-label="数字炸弹">数字炸弹</h1>
        <p class="app__subtitle">在 1 到 100 中找出隐藏的数字</p>
      </header>

      <section class="controls">
        <button id="startButton" class="button button--primary" type="button" aria-pressed="false">开始</button>
      </section>

      <section class="board__wrapper">
        <div id="board" class="board" role="grid" aria-label="数字网格 1 到 100"></div>
      </section>

      <div id="overlay" class="overlay" aria-hidden="true">
        <div class="overlay__content">
          <div class="overlay__text">游戏结束</div>
          <div class="overlay__hint">点击「重新开始」再来一局</div>
        </div>
      </div>
    </main>

    <script>
      (() => {
        const startButton = document.getElementById('startButton');
        const board = document.getElementById('board');
        const overlay = document.getElementById('overlay');

        /**
         * Game state
         */
        let secretNumber = null; // 1..100
        let gameStarted = false;
        // Web Audio for explosion SFX
        let audioContext = null;

        function getAudioContext() {
          if (!audioContext) {
            const Ctx = window.AudioContext || window.webkitAudioContext;
            audioContext = new Ctx();
          }
          if (audioContext.state === 'suspended') {
            // On iOS/Safari, resume after user gesture
            audioContext.resume().catch(() => {});
          }
          return audioContext;
        }

        function playExplosion() {
          const ctx = getAudioContext();
          const now = ctx.currentTime;

          // Noise burst with decay
          const duration = 0.8;
          const frames = Math.floor(ctx.sampleRate * duration);
          const noiseBuffer = ctx.createBuffer(1, frames, ctx.sampleRate);
          const data = noiseBuffer.getChannelData(0);
          for (let i = 0; i < frames; i += 1) {
            const t = i / frames;
            const envelope = Math.pow(1 - t, 2); // quick decay
            data[i] = (Math.random() * 2 - 1) * envelope;
          }
          const noise = ctx.createBufferSource();
          noise.buffer = noiseBuffer;
          const lp = ctx.createBiquadFilter();
          lp.type = 'lowpass';
          lp.frequency.setValueAtTime(900, now);
          lp.Q.setValueAtTime(0.7, now);
          const noiseGain = ctx.createGain();
          noiseGain.gain.setValueAtTime(0.9, now);
          noiseGain.gain.exponentialRampToValueAtTime(0.0001, now + duration);
          noise.connect(lp).connect(noiseGain).connect(ctx.destination);
          noise.start(now);
          noise.stop(now + duration);

          // Low thump pitch drop
          const osc = ctx.createOscillator();
          osc.type = 'sine';
          osc.frequency.setValueAtTime(140, now);
          osc.frequency.exponentialRampToValueAtTime(42, now + 0.5);
          const thumpGain = ctx.createGain();
          thumpGain.gain.setValueAtTime(0.6, now);
          thumpGain.gain.exponentialRampToValueAtTime(0.0001, now + 0.5);
          osc.connect(thumpGain).connect(ctx.destination);
          osc.start(now);
          osc.stop(now + 0.5);
        }

        function generateGrid() {
          board.innerHTML = '';
          for (let i = 1; i <= 100; i += 1) {
            const button = document.createElement('button');
            button.className = 'cell';
            button.type = 'button';
            button.textContent = String(i);
            button.setAttribute('role', 'gridcell');
            button.setAttribute('aria-label', `数字 ${i}`);
            button.dataset.value = String(i);
            board.appendChild(button);
          }
        }

        function randomInt(min, max) {
          return Math.floor(Math.random() * (max - min + 1)) + min;
        }

        function startGame() {
          gameStarted = true;
          startButton.textContent = '重新开始';
          startButton.setAttribute('aria-pressed', 'true');
          overlay.setAttribute('aria-hidden', 'true');
          // Unlock audio on user gesture
          try { getAudioContext(); } catch (_) {}
          // Reset grid
          Array.from(board.children).forEach((el) => {
            el.classList.remove('cell--hidden', 'cell--hit');
            el.disabled = false;
          });
          secretNumber = randomInt(1, 100);
          // console.log('secret', secretNumber);
        }

        function endGame() {
          gameStarted = false;
          startButton.textContent = '重新开始';
          startButton.setAttribute('aria-pressed', 'false');
          overlay.setAttribute('aria-hidden', 'false');
          // Disable remaining cells
          Array.from(board.children).forEach((el) => {
            el.disabled = true;
          });
        }

        function onCellClick(evt) {
          const target = evt.target;
          if (!(target instanceof HTMLElement)) return;
          if (!gameStarted) return;
          const value = Number(target.dataset.value);
          if (!Number.isFinite(value)) return;

          if (value === secretNumber) {
            target.classList.add('cell--hit');
            try { playExplosion(); } catch (_) {}
            endGame();
            return;
          }

          if (value < secretNumber) {
            // hide 1..value
            for (let i = 1; i <= value; i += 1) {
              const el = board.children[i - 1];
              if (el) el.classList.add('cell--hidden');
            }
          } else if (value > secretNumber) {
            // hide value..100
            for (let i = value; i <= 100; i += 1) {
              const el = board.children[i - 1];
              if (el) el.classList.add('cell--hidden');
            }
          }
        }

        // Init
        generateGrid();
        startButton.addEventListener('click', startGame);
        board.addEventListener('click', onCellClick);
      })();
    </script>
  </body>
</html>